function execute({ program, primitive, uniforms, buffer }) {
  let useBuffer = (next) => {
    if (buffer.data.isBuffer) {
      this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer.data.buffer)
      useProgram()
      this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null)
    } else {
      if (!buffer.data.length) return
      this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.glBuffer)
      this.gl.bufferData(
        this.gl.ARRAY_BUFFER,
        buffer.data,
        this.gl.DYNAMIC_DRAW
      )
      useProgram()
      this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null)
    }
  }

  let useProgram = () => {
    this.gl.useProgram(program.program)
    program.useUniforms(this, uniforms, () => {
      program.useAttrs(this, buffer.stride, buffer.offset, () => {
        this.gl.drawArrays(primitive, 0, buffer.count)
      })
    })
    this.gl.useProgram(null)
  }

  useBuffer()
}
